home *** CD-ROM | disk | FTP | other *** search
- /*
- 94/01/12 aih
- - Another major revision to put event handler functions into some
- sort of order by breaking them up into functional groups.
-
- 94/01/11 aih
- - Menu command handlers are passed a "const MenuPickType *pick"
- parameter instead of a "MenuPickType mc" parameter. This is
- marginally more efficient and it's more consistent with
- structure parameters in the rest of the code (which are nearly
- all passed by reference).
-
- 94/01/03 aih
- - After each event handler is called, if available memory has dropped
- below a certain threshold then segments are unloaded. This is done
- since calling an event handler typically loads the segment containing
- the code for the handler, often along with several other segments
- needed by the handler, but once the handler has finished executing
- those segments are no longer needed.
-
- 93/12/21 aih
- - major revisions to remove need to predefine an event kind,
- which anyway wasn't used for anything important; this will make
- it easier to add plug-in modules without having to recompile
- existing modules
-
- 93/12/17 aih
- - changed to use LLPtrLib to avoid duplicating linked-list code
-
- 93/10/18 aih
- - put file through another major revision to use tables
- containing pointers to event handlers. this instead of using
- switch statements and direct calls to the event handlers. this
- will help shrink object code size by allowing the linker to strip
- out unused libraries, and also remove the need to modify
- this file every time a new event kind is added.
-
- 93/03/?? aih
- - modified event library to use switch statements instead of previous
- inefficient method of table lookup for event handlers */
-
- #include <stdlib.h>
- #include <limits.h>
- #include <string.h>
- #include <AppleEvents.h>
- #include <DiskInit.h>
- #include "ByteLib.h"
- #include "DialogLib.h"
- #include "DrawLib.h"
- #include "EventLib.h"
- #include "EventPrivateLib.h"
- #include "KeyLib.h"
- #include "LowMemLib.h"
- #include "MacLib.h"
- #include "MathLib.h"
- #include "MemoryLib.h"
- #include "MenuLib.h"
- #include "NotifyLib.h"
- #include "RectangleLib.h"
- #include "ResourceConstantsLib.h"
- #include "ScreenLib.h"
- #include "SegmentLib.h"
- #include "SystemWindowLib.h"
- #include "WindowLib.h"
-
- /*----------------------------------------------------------------------------*/
- /* constants and globals */
- /*----------------------------------------------------------------------------*/
-
- /* Unload segments if the difference between the total free space and
- the maximum contiguous block is at least this amount. */
- #define UNLOAD_THRESHOLD (2048)
-
- /* Unload segments no more often than this interval. */
- #define UNLOAD_INTERVAL (20 * TICKS_SEC)
-
- /* interval between memory low warnings */
- #define WARN_INTERVAL (TICKS_MIN)
-
- Boolean gInBackground; /* true if application is in the background */
-
- struct {
- Boolean appleEvent; /* true if executing an Apple event */
- Boolean exit; /* if true then the event loop is exited */
- MemoryWarningType warned; /* highest warning level for which a
- low-memory alert was displayed */
- TicksType lastwarned; /* when last low-memory alert was displayed */
- } gEvent;
-
- /*----------------------------------------------------------------------------*/
- /* low memory */
- /*----------------------------------------------------------------------------*/
-
- /* The heap usually becomes fragmented when a segment is unloaded while
- there are still locked segments below it in the heap (segments are
- loaded at the top of the heap). Since MoveHHi won't move newly loaded
- segments past a locked segment, the space now vacated by the unloaded
- segment will not be filled as more segments are loaded. Therefore,
- we unload all of the segments at the top of the event loop to
- ensure that there are no segments in use that could fragment the heap.
-
- The heap is considered fragmented if the total free space is significantly
- greater than the maximum contiguous block that could be allocated.
- To prevent the application from constantly unloading segments,
- when unloading them has no effect on fragmentation, we use
- a delay of several seconds. */
- static void DefragmentHeap(void)
- {
- static TicksType lastUnload;
- long total, contig;
-
- PurgeSpace(&total, &contig);
- if (contig + UNLOAD_THRESHOLD < total &&
- TickCount() - lastUnload > UNLOAD_INTERVAL)
- {
- SegmentsUnload();
- lastUnload = TickCount();
- }
- }
-
- /* check for low memory situation and disable features (in order
- of severity of memory shortage) until there's enough memory */
- static void EvtMemoryLow(MemoryWarningType warning)
- {
- static Boolean recovering; /* prevent recursive calls */
- static TicksType lastfree; /* time when we last tried to free memory */
- Boolean canfail = false;
-
- if (recovering) return;
- TRY {
-
- recovering = true;
-
- /* recovering from a low-memory situation is a critical operation
- which shouldn't be prevented due to lack of some memory, since
- we're trying to make memory available */
- canfail = MemCanFail(false);
-
- /* terminate immediately, before more than just this application crashes */
- if (warning >= MEM_WARNING_FATAL)
- ExitToShell();
-
- /* Warn user. There are several warning messages, each corresponding to
- a memory warning level. Each message is displayed only once, and if
- a more severe message has already been displayed then less severe
- messages are skipped. Since memory usage may be borderline, resulting
- in low-memory situations occuring very frequently, we avoid
- displaying warning messages unless either the situation worsens
- or some time (e.g., 1 minute) has passed since the last warning. */
- if (gEvent.warned < warning ||
- (! gEvent.warned && TickCount() - gEvent.lastwarned > WARN_INTERVAL))
- {
- switch (warning) {
- case MEM_WARNING_LOW:
- NotifyCaution(RLS_ALERT_MEMORY_LOW);
- break;
- case MEM_WARNING_VERY_LOW:
- NotifyCaution(RLS_ALERT_MEMORY_VERY_LOW);
- break;
- case MEM_WARNING_CRITICAL:
- NotifyCaution(RLS_ALERT_MEMORY_CRITICAL);
- break;
- }
- gEvent.lastwarned = TickCount();
- gEvent.warned = warning;
- }
-
- /* Try to free up enough memory. A delay is used so that the
- application doesn't spend all of its time trying to free
- memory if none is available. */
- if (TickCount() - lastfree > TICKS_SEC) {
- const EventTableType *table;
- short i, ntable;
-
- UnloadScrap();
- ntable = EventTableCount();
- for (i = 0; i < ntable; i++) {
- table = EventTableGet(i);
- if (table->objectType.memorylow) {
- table->objectType.memorylow();
- }
- }
- lastfree = TickCount();
- }
- MemCanFail(canfail);
- recovering = false;
- } CATCH {
- recovering = false;
- } ENDTRY;
- }
-
- /* check memory status */
- static void EvtMemoryCheck(void)
- {
- if (MemWarning()) {
- /* tell user about the low memory situation and take steps to correct it */
- EvtMemoryLow(MemWarning());
- }
- else if (TickCount() - gEvent.lastwarned > WARN_INTERVAL) {
- /* reset warning indicator so user will be alerted
- next time memory is low */
- gEvent.warned = MEM_WARNING_NONE;
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* menu events */
- /*----------------------------------------------------------------------------*/
-
- /* dispatch a menu command */
- static void EvtMenu(const MenuPickType *pick)
- {
- const EventTableType *table;
- Boolean handled = false;
- short i, ntable;
-
- require(MenuEnabled(pick->menu, 0) && MenuEnabled(pick->menu, pick->item));
- handled = SystemDoMenu(pick);
- table = FocusTable();
- if (! handled && table && table->focusObject.menu)
- handled = table->focusObject.menu(FocusObject(), pick);
- ntable = EventTableCount();
- for (i = 0; ! handled && i < ntable; i++) {
- table = EventTableGet(i);
- if (table->objectType.menu)
- handled = table->objectType.menu(pick);
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* adjust menu, cursor, and sleep period */
- /*----------------------------------------------------------------------------*/
-
- /* adjust the menus and redraw menu bar if necessary */
- static void EvtAdjustMenu(void)
- {
- const EventTableType *table;
- short i, ntable;
- Boolean canfail;
- long flags;
-
- /* When memory is low, even adjusting the menus could fail since it may
- require some allocation. To prevent an infinite sequence of "Out of
- memory alerts" (which are generated in response to the out of memory
- alert itself, as well as simply clicking in the menu bar), we set
- the canfail flag to false. */
- canfail = MemCanFail(false);
- flags = MenuBarState();
- MenuAdjust();
- SystemAdjustMenu();
- table = FocusTable();
- if (table && table->focusObject.adjustmenu)
- table->focusObject.adjustmenu(FocusObject());
- ntable = EventTableCount();
- for (i = 0; i < ntable; i++) {
- table = EventTableGet(i);
- if (table->objectType.adjustmenu)
- table->objectType.adjustmenu();
- }
- if (flags != MenuBarState()) {
- HiliteMenu(0);
- DrawMenuBar();
- }
- MemCanFail(canfail);
- }
-
- /* adjust the cursor */
- static RgnHandle EvtAdjustCursor(void)
- {
- static RgnHandle cursorRgn;
- EventType *list;
- Boolean arrow;
- Point where;
-
- arrow = true;
- if (! cursorRgn) {
- cursorRgn = NewRgn();
- FailNIL(cursorRgn);
- }
- CopyRgn(ScreenRgnAll(), cursorRgn);
- GetMouse(&where);
- LocalToGlobal(&where);
- if (SystemIsActive())
- arrow = false;
- for (list = FocusList(); arrow && list; list = EventNext(list)) {
- if (list->table->focusWindow.adjustcursor)
- arrow = ! list->table->focusWindow.adjustcursor(list->object, where, cursorRgn);
- }
- if (arrow)
- DrawCursor(arrowCursor);
- return(cursorRgn);
- }
-
- /* return time to sleep to pass to WNE */
- static TicksType EvtAdjustSleep(void)
- {
- EventType *list = NULL;
- TicksType sleep = LONG_MAX;
-
- if (SystemIsActive())
- sleep = 0;
- for (list = FocusList(); sleep > 0 && list; list = EventNext(list)) {
- if (list->table->focusWindow.adjustsleep)
- sleep = min(sleep, list->table->focusWindow.adjustsleep(list->object));
- }
- return(sleep);
- }
-
- /*----------------------------------------------------------------------------*/
- /* null event */
- /*----------------------------------------------------------------------------*/
-
- /* handle a null event */
- static void EvtNullEvent(EventRecord *event)
- {
- const EventTableType *table;
-
- table = FocusTable();
- if (table && table->focusObject.idle)
- table->focusObject.idle(FocusObject());
- }
-
- /*----------------------------------------------------------------------------*/
- /* closing windows */
- /*----------------------------------------------------------------------------*/
-
- static void EvtClose(WindowPtr window)
- {
- EventType *list;
-
- for (list = WinObjects(window); list; list = EventNext(list)) {
- if (list->table->window.close) {
- list->table->window.close(list->object);
- break;
- }
- }
- }
-
- static void EvtCloseAll(WindowPtr window)
- {
- if (window) {
- EvtCloseAll((WindowPtr) ((WindowPeek) window)->nextWindow);
- if (WinHasExtra(window))
- EvtClose(window);
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* mousedown and mouseup */
- /*----------------------------------------------------------------------------*/
-
- /* tell application which object was typed in or clicked in, or use nil
- object and id if clicked outside of object (e.g., text field is being
- closed, window is being deactivated) */
- static void EvtClicked(WindowPtr window, EventObjectType object, EventIDType id)
- {
- EventType *list;
-
- if (window) {
- if (id)
- DlgClick(window, id);
- for (list = WinObjects(window); list; list = EventNext(list)) {
- if (list->table->focusWindow.clicked)
- list->table->focusWindow.clicked(list->object, object, id);
- }
- }
- }
-
- static void EvtMouseDownInMenuBar(EventRecord *event)
- {
- long menu = 0;
-
- EvtClicked(FocusWindow(), NULL, 0);
- EvtAdjustMenu();
- menu = MenuSelect(event->where);
- if (HiWord(menu)) {
- MenuPickType pick = MenuPick(HiWord(menu), LoWord(menu));
- EvtMenu(&pick);
- HiliteMenu(0);
- }
- }
-
- static void EvtMouseDownInSystemWindow(EventRecord *event, WindowPtr window)
- {
- SystemClick(event, window);
- }
-
- static void EvtMouseDownInContent(EventRecord *event, WindowPtr window)
- {
- EventType *list = NULL;
- EventType *found = NULL;
- Point where = event->where;
- Boolean click = true;
-
- /* We need to make sure the window is an application window since
- it may be a "Looking for LaserWriter..." dialog displayed by
- the Print Manager. */
- if (WinHasExtra(window)) {
-
- /* Select window if it isn't the front window in its layer. Floating
- windows will process the click even if they weren't the front window,
- while all other windows will be selected but will not process
- the click. */
- if (window != FocusWindow() &&
- (WinLayer(window) != WIN_LAYER_FLOAT ||
- window != WinFirstVisible(WIN_LAYER_FLOAT) ||
- SystemIsActive()))
- {
- if (WinLayer(window) != WIN_LAYER_FLOAT)
- click = false;
- WinSelect(window);
- }
- if (click) {
- /* send the event to the object containing the point clicked */
- GlobalToPort(&where, window);
- for (list = WinObjects(window); list && ! found; list = EventNext(list)) {
- if (list->table->focusWindow.within) {
- if (list->table->focusWindow.within(list->object, where))
- found = list;
- }
- }
- if (found && found->table->focusWindow.mousedown) {
- if (! found->table->focusWindow.mousedown(found->object, event))
- found = NULL;
- }
- EvtClicked(window, found ? found->object : NULL, found ? found->id : 0);
- }
- }
- }
-
- static void EvtMouseDownInDrag(EventRecord *event, WindowPtr window)
- {
- if ((event->modifiers & cmdKey) == 0)
- WinSelect(window);
- WinDrag(window, event->where);
- }
-
- static void EvtMouseDownInGrow(EventRecord *event, WindowPtr window)
- {
- Rect oldSize, newSize;
-
- WinPortRect(window, &oldSize);
- WinGrow(window, event->where);
- WinPortRect(window, &newSize);
- WinResize(window, RectWidth(&newSize) - RectWidth(&oldSize),
- RectHeight(&newSize) - RectHeight(&oldSize));
- }
-
- static void EvtMouseDownInGoAway(EventRecord *event, WindowPtr window)
- {
- if (TrackGoAway(window, event->where))
- EvtClose(window);
- }
-
- static void EvtMouseDownInZoom(EventRecord *event, WindowPtr window)
- {
- Rect oldSize, newSize;
- short part;
-
- /* need to call FindWindow after WinZoomPrepare */
- WinZoomPrepare(window);
- part = FindWindow(event->where, &window);
- if (TrackBox(window, event->where, part)) {
- WinPortRect(window, &oldSize);
- WinZoom(window, part);
- WinPortRect(window, &newSize);
- WinResize(window, RectWidth(&newSize) - RectWidth(&oldSize),
- RectHeight(&newSize) - RectHeight(&oldSize));
- }
- }
-
- /* dispatch a mouseDown event to the appropriate function */
- static void EvtMouseDown(EventRecord *event)
- {
- WindowPtr window = NULL;
-
- ScreenSet(ScreenContainingPt(event->where));
- switch (FindWindow(event->where, &window)) {
- case inMenuBar: EvtMouseDownInMenuBar(event); break;
- case inSysWindow: EvtMouseDownInSystemWindow(event, window); break;
- case inContent: EvtMouseDownInContent(event, window); break;
- case inDrag: EvtMouseDownInDrag(event, window); break;
- case inGrow: EvtMouseDownInGrow(event, window); break;
- case inGoAway: EvtMouseDownInGoAway(event, window); break;
- case inZoomIn: EvtMouseDownInZoom(event, window); break;
- case inZoomOut: EvtMouseDownInZoom(event, window); break;
- }
- }
-
- static void EvtMouseUp(EventRecord *event)
- {
- ScreenSet(ScreenContainingPt(event->where));
- }
-
- /*----------------------------------------------------------------------------*/
- /* keydown and autokey */
- /*----------------------------------------------------------------------------*/
-
- /* handle command key events */
- static void EvtKeyDownCommand(EventRecord *event, unsigned char key)
- {
- EvtClicked(FocusWindow(), NULL, 0);
- EvtAdjustMenu();
- if ((event->modifiers & cmdKey) != 0) {
- long menu = MenuKey(key);
- if (HiWord(menu)) {
- MenuPickType pick = MenuPick(HiWord(menu), LoWord(menu));
- EvtMenu(&pick);
- HiliteMenu(0);
- }
- }
- else
- EvtMenu(MenuCmdPick(KeyToCmd(event)));
- }
-
- /* handle all other keyDown events */
- static void EvtKeyDownOther(EventRecord *event)
- {
- const EventTableType *table = FocusTable();
-
- if (table && table->focusObject.keydown) {
- table->focusObject.keydown(FocusObject(), event);
- EvtClicked(FocusWindow(), FocusObject(), FocusID());
- }
- }
-
- /* handle all keyDown events */
- static void EvtKeyDown(EventRecord *event)
- {
- unsigned char key = event->message;
-
- if (! SystemIsActive()) {
- ScreenSet(ScreenContainingWindow(FocusWindow()));
- if ((event->modifiers & cmdKey) != 0 || KeyToCmd(event) != CMD_NONE) {
- if (event->what != autoKey)
- EvtKeyDownCommand(event, key);
- }
- else if (key == tabKey && FocusWindow() && WinHasTabList(FocusWindow())) {
- WinTab(FocusWindow());
- EvtClicked(FocusWindow(), FocusObject(), FocusID());
- }
- else
- EvtKeyDownOther(event);
- }
- }
-
- /* handle autoKey events */
- static void EvtAutoKey(EventRecord *event)
- {
- if ((event->modifiers & cmdKey) == 0)
- EvtKeyDown(event);
- }
-
- /*----------------------------------------------------------------------------*/
- /* disk inserted event */
- /*----------------------------------------------------------------------------*/
-
- /* handle a disk inserted event; from new "Inside Macintosh: Files", p5-10 */
- static void EvtDisk(EventRecord *event)
- {
- Point pt = { 120, 120 };
-
- if (HiWord(event->message) == noErr) {
- DILoad();
- (void) DIBadMount(pt, event->message);
- DIUnload();
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* operating system events */
- /*----------------------------------------------------------------------------*/
-
- /* handle a mouse moved event */
- static void EvtOSMouseMoved(EventRecord *event)
- {
- /* do nothing for now */
- }
-
- /* handle a suspend event */
- static void EvtOSSuspend(void)
- {
- const EventTableType *table;
- short i, ntable;
-
- ntable = EventTableCount();
- for (i = 0; i < ntable; i++) {
- table = EventTableGet(i);
- if (table->objectType.suspend)
- table->objectType.suspend();
- }
- gInBackground = true;
- }
-
- /* handle a resume event */
- static void EvtOSResume(void)
- {
- const EventTableType *table;
- short i, ntable;
-
- gInBackground = false;
- ntable = EventTableCount();
- for (i = 0; i < ntable; i++) {
- table = EventTableGet(i);
- if (table->objectType.resume)
- table->objectType.resume();
- }
- }
-
- /* the desk scrap has changed */
- static void EvtOSConvertClipboard(void)
- {
- /* do nothing for now */
- }
-
- /* dispatch an operating system event */
- static void EvtOS(EventRecord *event)
- {
- switch (HiByte(HiWord(event->message))) {
- case mouseMovedMessage:
- EvtOSMouseMoved(event);
- break;
- case suspendResumeMessage:
- if (event->message & resumeFlag)
- EvtOSResume();
- else
- EvtOSSuspend();
- if (event->message & convertClipboardFlag)
- EvtOSConvertClipboard();
- break;
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* update and activate events */
- /*----------------------------------------------------------------------------*/
-
- /* update all objects contained in the window specified in the event */
- static void EvtUpdate(EventRecord *event)
- {
- WindowPtr window = (WindowPtr) event->message;
- EventType *list = NULL;
-
- if (WinHasExtra(window)) {
- BeginUpdate(window);
- for (list = WinObjects(window); list; list = EventNext(list)) {
- if (list->table->window.update)
- list->table->window.update(list->object);
- }
- EndUpdate(window);
- }
- }
-
- /* update the objects' focus */
- static void EvtFocus(EventType *focus, Boolean flag)
- {
- if (focus->table->focusWindow.focus)
- focus->table->focusWindow.focus(focus->object, flag);
- }
-
- /* activate or deactivate all objects contained in the window */
- static void EvtActivate(WindowPtr window, Boolean activate)
- {
- EventType *list;
-
- if (! activate)
- EvtClicked(window, NULL, 0);
- if (WinFocus(window))
- EvtFocus(WinFocus(window), activate);
- for (list = WinObjects(window); list; list = EventNext(list)) {
- if (list->table->window.activate)
- list->table->window.activate(list->object, activate);
- }
- }
-
- /* handle an activate or deactivate event */
- static void EvtActive(EventRecord *event)
- {
- WindowPtr window = (WindowPtr) event->message;
- Boolean activate = (event->modifiers & activeFlag) != 0;
-
- if (WinHasExtra(window)) {
- if (WinLayer(window) == WIN_LAYER_FLOAT)
- window = WinNextVisibleNonFloat(window);
- if (window) {
- EvtActivate(window, activate);
- if (activate) {
- FocusWindowSet(window);
- EvtAdjustMenu();
- }
- else if (! GetCurActivate() || ! WinHasExtra(GetCurActivate())) {
- FocusWindowSet(NULL);
- EvtAdjustMenu();
- }
- }
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* high-level event */
- /*----------------------------------------------------------------------------*/
-
- static void EvtHighLevel(EventRecord *event)
- {
- Boolean oldAppleEvent;
-
- oldAppleEvent = gEvent.appleEvent;
- gEvent.appleEvent = true;
- (void) AEProcessAppleEvent(event);
- gEvent.appleEvent = oldAppleEvent;
- }
-
- /*----------------------------------------------------------------------------*/
- /* pre- and post- event filters */
- /*----------------------------------------------------------------------------*/
-
- /* Do any pre-event filtering. This is useful for disabling certain events,
- converting one type of event into a different event, or just handling
- an event before the regular processing takes place (for instance,
- to interpret command keys without calling MenuKey). */
- static void EvtFilterPre(EventRecord *event)
- {
- EventType *list;
-
- for (list = FocusList(); list; list = EventNext(list)) {
- if (list->table->focusWindow.prefilter)
- list->table->focusWindow.prefilter(list->object, event);
- }
- }
-
- /* do any post-event processing */
- static void EvtFilterPost(EventRecord *event)
- {
- EventType *list;
-
- for (list = FocusList(); list; list = EventNext(list)) {
- if (list->table->focusWindow.postfilter)
- list->table->focusWindow.postfilter(list->object, event);
- }
- }
-
- /*----------------------------------------------------------------------------*/
- /* executing events */
- /*----------------------------------------------------------------------------*/
-
- /* execute the event */
- static void EvtExecute(EventRecord *event)
- {
- EvtFilterPre(event);
- switch (event->what) {
- case nullEvent: EvtNullEvent(event); break;
- case mouseDown: EvtMouseDown(event); break;
- case mouseUp: EvtMouseUp(event); break;
- case keyDown: EvtKeyDown(event); break;
- case autoKey: EvtAutoKey(event); break;
- case updateEvt: EvtUpdate(event); break;
- case activateEvt: EvtActive(event); break;
- case diskEvt: EvtDisk(event); break;
- case osEvt: EvtOS(event); break;
- case kHighLevelEvent:EvtHighLevel(event); break;
- }
- EvtFilterPost(event);
- }
-
- /* get and execute one event */
- static void EvtGetAndExecuteOne(void)
- {
- EventRecord event;
-
- EventPreTasksExecute();
- EventGet(everyEvent, &event, EvtAdjustSleep(), EvtAdjustCursor());
- EvtExecute(&event);
- EventPostTasksExecute();
- }
-
- /*----------------------------------------------------------------------------*/
- /* external interface */
- /*----------------------------------------------------------------------------*/
-
- /*----------------------------------------------------------------------------*/
- /* executing events */
- /*----------------------------------------------------------------------------*/
-
- void EventMenu(const MenuPickType *pick)
- {
- EvtMenu(pick);
- }
-
- void EventAdjustMenu(void)
- {
- EvtAdjustMenu();
- }
-
- void EventFocus(EventType *focus, Boolean flag)
- {
- EvtFocus(focus, flag);
- }
-
- void EventActivate(WindowPtr window, Boolean activate)
- {
- EvtActivate(window, activate);
- }
-
- void EventExecute(EventRecord *event)
- {
- EvtExecute(event);
- }
-
- void EventOne(void)
- {
- EvtGetAndExecuteOne();
- }
-
- /*----------------------------------------------------------------------------*/
- /* event loops */
- /*----------------------------------------------------------------------------*/
-
- /* handle an error in the main event loop */
- static void EvtErrorMain(void)
- {
- OSErr err;
-
- TRY {
- MemCanFail(false);
- SegmentsUnloadEnable(true);
- err = FailReason();
- FailDisplay();
- FailClear();
- if (err == memFullErr) {
- /* unload segments so as much memory as possible is free and
- the heap is as compact as possible so that the application
- can try again */
- SegmentsUnload();
- }
- HiliteMenu(0);
- MemCanFail(true);
- } CATCH {
- /* This gets executed if, while trying to recover from an
- error, another error occurs. If this handler wasn't
- present the application would simply exit. Often, the
- second exception occurs when there's no more memory
- to display an error alert. Instead of just exiting
- (and losing unsaved files), we reset the error
- condition and try to reenter the event loop. Should
- a third exception occur while trying to recover
- from the first two then the program will exit. */
- FailClear();
- HiliteMenu(0);
- MemCanFail(true);
- NOPROPAGATE;
- } ENDTRY;
- }
-
- /* run the event loop until it is exited (event loops may be nested
- recursively) */
- void EventLoop(void)
- {
- while (! gEvent.exit)
- EvtGetAndExecuteOne();
- gEvent.exit = false;
- }
-
- /* the main event loop of the application */
- static void EvtLoopMain(void)
- {
- TRY {
- while (! gEvent.exit) {
- DefragmentHeap();
- EvtMemoryCheck();
- EvtGetAndExecuteOne();
- }
- EvtCloseAll(FrontWindow());
- } CATCH {
- EvtErrorMain();
- RETRY;
- } ENDTRY;
- }
-
- /* Call this after initialization to enter the main event loop.
- This event loop can not be nested. */
- void EventLoopMain(void)
- {
- EvtLoopMain();
- }
-
- /* set a flag which will cause the current event loop to exit */
- void EventLoopExit(Boolean flag)
- {
- gEvent.exit = flag;
- }
-
- /*----------------------------------------------------------------------------*/
- /* utility functions */
- /*----------------------------------------------------------------------------*/
-
- /* true if the application is in the background */
- Boolean EventInBackground(void)
- {
- return(gInBackground);
- }
-
- /* true if the application is executing an Apple Event */
- Boolean EventInAppleEvent(void)
- {
- return(gEvent.appleEvent);
- }
-
- /* Start interacting with the user. Call this before creating a dialog
- or an alert that requires user interaction. */
- void EventInteractWithUser(void)
- {
- if (EventInAppleEvent())
- FailOSErr(AEInteractWithUser(kAEDefaultTimeout, NULL, NULL));
- }
-
- /* Call GetNextEvent or WaitNextEvent, depending on which one is available.
- The parameters to this function are identical to those to WaitNextEvent.
- If GetNextEvent is called the extra parameters are ignored. */
- Boolean EventGet(short mask, EventRecord *event, TicksType sleep, RgnHandle cursor)
- {
- Boolean result = false;
-
- if (MacHasWNE())
- result = WaitNextEvent(mask, event, sleep, cursor);
- else {
- SystemTask();
- result = GetNextEvent(mask, event);
- }
- if (! result) {
- /* make sure it's a null event, even if the system thinks otherwise, e.g.,
- some desk accessory events (see comment in TranSkell event loop) */
- event->what = nullEvent;
- }
- return(result);
- }
-